#pragma once

#include "math/maths.h"
#include <vector>
#include <Includes.h>

class CSceneNode
{
private:
    friend class CSceneTree;

protected:
    maths::CMatrix4x4f &m_L2W; // Local-2-world
	const mBool m_bL2WCreated;
	mBool m_bL2WChanged;

    maths::CMatrix4x4f  m_L2P; // Local-2-parent
    CSceneNode *m_pParent;
    std::vector <CSceneNode *> m_Childs;

	maths::CAABox m_AABoundBox;

public:
	CSceneNode               ( CSceneNode *a_Parent = NULL );
    CSceneNode               ( maths::CMatrix4x4f &a_L2W, CSceneNode *a_Parent = NULL );
    virtual ~CSceneNode      ( );

    mVoid UpdateL2W          ( ); // L2W = L2P * parent->L2W
	mBool SetL2WChanged      ( );

    maths::CMatrix4x4f GetL2P( ); 
	mVoid              SetL2P( maths::CMatrix4x4f &a_L2P );
    maths::CMatrix4x4f GetL2W( );

    CSceneNode *Parent       ( );

    mVoid AddChild          ( CSceneNode * a_Node );

	maths::CAABox &BoundBox();
};

class CSceneNodeControl
{
protected:
    CSceneNode *m_Node;

public:
    CSceneNodeControl      ( CSceneNode * a_Node );
    /* operating with L2P */
    mBool SetPos           ( maths::CVector4f &a_Pos );
    mVoid SetNode          ( CSceneNode * a_Node );
    mBool Move             ( maths::CVector4f &a_Delta );
    //mBool Rotate           ( maths::CVector4f &a_Dir, mFloat a_Angle );
	mBool Rotate           ( maths::CVector4f &a_Vector );
    mBool RotateInP2W      ( maths::CVector4f &a_Dir, mFloat a_Angle );
    mBool Scale            ( maths::CVector4f &a_Scale );
    mBool Scale            ( mFloat a_fXScale, mFloat a_fYScale, mFloat a_fZScale );
};

class CSceneNodeRootFunctor
{
public:
    virtual mUInt operator () ( CSceneNode * a_Node ) = 0;
};

class CSceneNodeLeafFunctor
{
public:
	virtual mUInt operator () ( CSceneNode * a_Node ) = 0;
};

class CSceneTree
{
private:
    /* "World" is the root of the tree, some kind of a "dummy" */
    static CSceneNode *m_World;
    //Debug *m_pDebug;

public:
    CSceneTree       ( );
    ~CSceneTree      ( );

    mBool AddChild   ( CSceneNode *a_Parent, CSceneNode *a_Child );

	maths::CAABox &BoundBox ( );

	enum IterateResult
	{
		IRESULT_CONTINUE = 0,
		IRESULT_SKIPCHILD   ,
		IRESULT_STOP
	};

    static mUInt Iterate ( CSceneNodeRootFunctor &a_pRootFunctor, CSceneNode *a_pRoot = m_World );
    static mUInt Iterate ( CSceneNodeLeafFunctor &a_pLeafFunctor, CSceneNode *a_pRoot = m_World );
};